home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / Source / curses / v_maccur.c < prev    next >
Text File  |  1994-05-02  |  47KB  |  1,619 lines

  1. /*    File v_maccur.c:
  2.  *        Machine specific part of curses implementation for Macintosh.
  3.  *        Also includes rudimentary replacements for stdio functions.
  4.  *
  5.  *     Copyright (c) 1994
  6.  *    by Robert Zimmerman
  7.  *
  8.  *  This code may be included in any work, public or private, with the
  9.  *  exception of creating a commercial curses-compatible subroutine
  10.  *  library.  (In other words, use the code all you want, but please don't
  11.  *  rip off the author by reselling this code as your own).
  12.  *
  13.  */
  14.  
  15. #include <AppleEvents.h>
  16. #include <limits.h>
  17. #include <ctype.h>
  18. #include <stdarg.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <signal.h>
  22. #include "curses.h"
  23.  
  24. /****
  25. * Resources expected by this code are:
  26. *    An ALRT and DITL to put up alerts with the function maccur_cpu_share (see macro ALERT_RSRC_ID).
  27. *    A MENU and MBAR to draw the menu (which includes only the apple menu) (see macro MENU_RES_ID).
  28. *
  29. *    Optionally, an ALRT and DITL for the "About x..." menu item (see variable _maccur_about_res_id).
  30. ****/
  31.  
  32. /****
  33. * First some macros for font, screen setup, etc:
  34. ****/
  35.  
  36. #define X_MARGIN 2
  37. #define Y_MARGIN 4
  38. #define Y_PIX_WIN (rowheight_pix * _maccur_lines + Y_MARGIN)
  39. #define X_PIX_WIN (charwid_pix * _maccur_cols + 2 * X_MARGIN)
  40.  
  41. /****
  42. * ROW/COL_TO_PIX determine pen position to write character at row/col.
  43. * First row/column is 0/0.
  44. ****/
  45.  
  46. #define COL_TO_PIX(col) ((col) * charwid_pix + X_MARGIN)
  47. #define ROW_TO_PIX(row) (((row) + 1) * rowheight_pix)
  48.  
  49. #define MAX_OUT_STRSEG 132            /* Max number of parts of a single character row (distinguished by writing attrib. */
  50. #define MAX_TYPEAHEAD 32            /* Number of keystrokes that will be buffered. */
  51. #define FLASH_TICKS 8                /* Flash cursor 2x second. */
  52. #define WINDO_TOP_ON_SCREEN 40        /* Default position of window on screen. */
  53. #define WINDO_LEFT_ON_SCREEN 5
  54. #define ALERT_RSRC_ID 128            /* ALRT id for generalize alert. */
  55. #define MENU_RES_ID 128                /* MBAR id for putting up (not much of a) menu. */
  56.  
  57. #define TST_BIT(i, b) ((i) & (1 << (b)))
  58. #define SET_BIT(b) (1 << (b))
  59.  
  60. enum {
  61.     MACCUR_RETURN_ON_IDLE_BIT,
  62.     MACCUR_RETURN_ON_CHAR_BIT
  63. };
  64.  
  65. typedef struct key_evnt_strct {                /* Struct in which to buffer keyboard events. */
  66.     long msg;
  67.     short mod;
  68. } KEY_EVENT;
  69.  
  70. static KEY_EVENT typebuf[MAX_TYPEAHEAD];    /* Buffer for keyboard events. */
  71.  
  72. /****
  73. * The following can be modified before curses is initialized
  74. * in order to customize display, etc:
  75. ****/
  76.  
  77. int _maccur_cols = 80;                        /* Window will be initialized to this size. */
  78. int _maccur_lines = 25;
  79. char *_maccur_font_name = "Monaco";            /* Font to use (C string). */
  80. int _maccur_font_size = 9;                    /* Size of font. */
  81. int _maccur_handle_break_option = MACCUR_EXIT_ON_BREAK;    /* This determines what happens on CMD-. (see enum in macurses.h). */
  82. int _maccur_about_res_id;                    /* Resource id alert to display if About... is chosen from apple menu. */
  83. char *_maccur_pgm_name = "Curses";            /* Program name for about and window title. */
  84. int _maccur_fg_sleep_ticks = 1;                /* How much can WaitNextEvent sleep in foreground. */
  85. int _maccur_bg_sleep_ticks = 2;                /* How much can WaitNextEvent sleep in background. */
  86. int _maccur_io_sleep_dvsr = 1;                /* How many of the output calls (maccur_printf, etc) call maccur_cpu_share. */
  87.                                             /*   (1/_maccur_io_sleep_dvsr of output calls will call maccur_cpu_share). */
  88.  
  89. static int rowheight_pix;                    /* Screen dimensions for each character. */
  90. static int charwid_pix;
  91. static short font_num;                        /* Writing font number. */
  92. static short font_res_id;                    /* Font resource ID. */
  93. static int show_cursor_flag;                /* TRUE if cursor should be flashed. */
  94. static Rect cursor_rect;                    /* Cursor, as a Rect. */
  95. static WindowPtr the_windo;                    /* Program window. */
  96. static long last_flash_when;                /* Keep track of when cursor flashed. */
  97. static int in_background_flag;                /* Keep track of program foreground/bkground state. */
  98. static int cursor_inverted;                    /* True if cursor is currently inverted. */
  99. static int typeahead_cnt;                    /* How many characters are waiting in typebuf. */
  100. static int typeahead_indx;                    /* Where does next character go in typebuf. */
  101. static int outchar_indx;                    /* Where does next character come out of typebuf. */
  102. static chtype *screen_char_arry;            /* Array holding screen contents. */
  103. static FontInfo fnt_info;                    /* Description of writing font. */
  104. static int maccur_about_mitm;                /* 1 if there is an About... item in apple menu. */
  105. static int maccur_has_menu;                    /* True if MBAR resource was found and menu put up. */
  106.  
  107. static int direct_curs_pos_row;                /* Keep track of cursor position when in direct (non-curses) mode. */
  108. static int direct_curs_pos_col;
  109.  
  110. static int cpu_share_rot_cnt;                /* When this reaches _maccur_io_sleep_dvsr its time to share CPU. */
  111.  
  112. /********
  113. **
  114. **    maccur_init_toolbox:  Initialize mac stuff.
  115. **
  116. **
  117. ********/
  118.  
  119. static void maccur_init_toolbox(void)
  120. {
  121.     InitGraf(&thePort);
  122.     InitFonts();
  123.     FlushEvents(everyEvent, 0);
  124.     InitWindows();
  125.     InitMenus();
  126.     TEInit();
  127.     InitDialogs(0L);
  128.     InitCursor();
  129.     MaxApplZone();
  130. }
  131.  
  132. /********
  133. **
  134. **    event_do_nothing:  Do nothing in response to apple events.
  135. **
  136. **
  137. ********/
  138.  
  139. static pascal OSErr event_do_nothing(
  140. const AppleEvent *theAppleEvent,
  141. AppleEvent *reply,
  142. long refCon
  143. ) {
  144.     return 0;
  145. }
  146.  
  147. /********
  148. **
  149. **    quit_app:  Quit application in response to apple event.
  150. **        This is fairly severe -- Should put up a dialogue box?
  151. **
  152. **
  153. ********/
  154.  
  155. static pascal OSErr quit_app(
  156. const AppleEvent *theAppleEvent,
  157. AppleEvent *reply,
  158. long refCon
  159. ) {
  160.     ExitToShell();
  161.     return 0;
  162. }
  163.  
  164. /********
  165. **
  166. **    maccur_init_event: Initialize handlers (such as they are) for
  167. **        required apple events.
  168. **
  169. **
  170. ********/
  171.  
  172. static void maccur_init_event(void)
  173. {
  174.     AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
  175.                     event_do_nothing, 0L, FALSE);
  176.     AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
  177.                     event_do_nothing, 0L, FALSE);
  178.     AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
  179.                     event_do_nothing, 0L, FALSE);
  180.     AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
  181.                     quit_app, 0L, FALSE);
  182. }
  183.  
  184. /********
  185. **
  186. **    maccur_get_font_info:  Search for resouce for desired font via FOND resource.
  187. **        Return dimension of characters for sizing of window.  There must be an
  188. **        easier way to determine the required window size b4 putting the window
  189. **        up (and without putting a fixed size window in resource file).
  190. **
  191. **    Returns:
  192. **        TRUE if font resource found, else FALSE.
  193. **
  194. **
  195. ********/
  196.  
  197. static int maccur_get_font_info(
  198. char *font_name,            /* -R- Name of desired font. */
  199. int font_pts,                /* -R- Size of desired font. */
  200. short *font_num_ptr,        /* -W- Return font number. */
  201. short *font_id_ptr,            /* -W- Return font resource id. */
  202. int *rowheight_pix_ptr,        /* -W- Return height of font. */
  203. int *charwid_pix_ptr        /* -W- Return width of font. */
  204. ) {
  205.     ResType res_typ;
  206.     Handle rsrc_ptr;
  207.     FamRec *fnt_fam_ptr;
  208.     FontAssoc *fnt_cnt_ptr;
  209.     AsscEntry *fnt_assc_list_ptr;
  210.     FontRec *fnt_rec_ptr;
  211.     int i;
  212.     char buf[256];
  213.  
  214.     memcpy(&res_typ, "FOND", sizeof(res_typ));
  215.     if ((rsrc_ptr = GetNamedResource(res_typ, (ConstStr255Param) font_name)) == NULL)
  216.         return FALSE;
  217.  
  218.     GetResInfo(rsrc_ptr, font_id_ptr, &res_typ, (unsigned char *) buf);
  219.     if (ResError() != noErr) return FALSE;
  220.  
  221.     fnt_fam_ptr = *((FamRec **)rsrc_ptr);
  222.     fnt_cnt_ptr = (FontAssoc *)(fnt_fam_ptr + 1);
  223.     fnt_assc_list_ptr = (AsscEntry *)(fnt_cnt_ptr + 1);
  224.  
  225.     *font_num_ptr = fnt_fam_ptr->ffFamID;
  226.  
  227.     for (i = 0; i < fnt_cnt_ptr->numAssoc + 1; i++)
  228.     {
  229.         if ((fnt_assc_list_ptr + i)->fontSize == font_pts &&
  230.                 (fnt_assc_list_ptr + i)->fontStyle == 0)
  231.             break;
  232.     }
  233.  
  234.     if (i == fnt_cnt_ptr->numAssoc + 1) return FALSE;
  235.  
  236.     fnt_rec_ptr = NULL;
  237.     if ((fnt_assc_list_ptr + i)->fontID == *font_id_ptr * 128 + font_pts)
  238.     {
  239.         memcpy(&res_typ, "FONT", sizeof(res_typ));
  240.         if ((rsrc_ptr = GetResource(res_typ, *font_id_ptr)) != NULL)
  241.             fnt_rec_ptr = *((FontRec **)rsrc_ptr);
  242.     }
  243.  
  244.     if (fnt_rec_ptr != NULL)
  245.     {
  246.         memcpy(&res_typ, "NFNT", sizeof(res_typ));
  247.         if ((rsrc_ptr = GetResource(res_typ, *font_id_ptr)) != NULL)
  248.             fnt_rec_ptr = *((FontRec **)rsrc_ptr);
  249.     }
  250.  
  251.     if (fnt_rec_ptr == NULL) return FALSE;
  252.  
  253.     *rowheight_pix_ptr = fnt_rec_ptr->fRectHeight;
  254.     *charwid_pix_ptr = fnt_rec_ptr->fRectWidth;
  255.  
  256.     return TRUE;
  257. }
  258.  
  259. /********
  260. **
  261. **    maccur_init_window: Size and open curses window.
  262. **
  263. **
  264. ********/
  265.  
  266. static void maccur_init_window(void)
  267. {
  268.     Rect windo_rect;
  269.     ResType font_res;
  270.     FontRec *fnt_rec_ptr;
  271.     Handle rsrc_ptr;
  272.     char windo_titl[128], font_name[32];
  273.  
  274.     font_name[0] = strlen(_maccur_font_name);                            /* Copy font name to local pascal string. */
  275.     strcpy(font_name + 1, _maccur_font_name);
  276.  
  277.     if (_maccur_font_size <= 0) _maccur_font_size = 9;                    /* Make sure font size is reasonable. */
  278.  
  279.     windo_rect.top = WINDO_TOP_ON_SCREEN;
  280.     windo_rect.left = WINDO_LEFT_ON_SCREEN;
  281.     if (maccur_get_font_info(font_name, _maccur_font_size,                /* Try to find font dimensions before putting up window. */
  282.                                 &font_num, &font_res_id,
  283.                                 &rowheight_pix, &charwid_pix))
  284.     {
  285.         windo_rect.bottom = windo_rect.top + Y_PIX_WIN;
  286.         windo_rect.right = windo_rect.left + X_PIX_WIN;
  287.     }
  288.     else
  289.     {
  290.         GetFNum((ConstStr255Param) font_name, &font_num);                /* If can't find them, put it up and then resize it. */
  291.         if (font_num == 0)
  292.         {
  293.             maccur_alert_msg("Could not access font '%s'!",
  294.                                 _maccur_font_name);
  295.             ExitToShell();
  296.         }
  297.         windo_rect.bottom = windo_rect.top + 10;
  298.         windo_rect.right = windo_rect.left + 10;
  299.     }
  300.  
  301.     strcpy(windo_titl, (_maccur_pgm_name == NULL ||
  302.                                 *_maccur_pgm_name == '\0') ?
  303.                                     "Curses" : _maccur_pgm_name);
  304.     if ((the_windo = NewWindow(nil, &windo_rect,
  305.                                 CtoPstr(windo_titl), TRUE,
  306.                                 noGrowDocProc, (WindowPtr)-1L,
  307.                                 FALSE, (long)nil)) == nil)
  308.     {
  309.         maccur_alert_msg("Could not initialize program window!");
  310.         ExitToShell();
  311.     }
  312.  
  313.     SetPort(the_windo);
  314.  
  315.     if (font_num != 0)
  316.         TextFont(font_num);
  317.  
  318.     TextSize(_maccur_font_size);
  319.     GetFontInfo(&fnt_info);
  320.     if (charwid_pix != fnt_info.widMax ||
  321.             rowheight_pix != fnt_info.ascent + fnt_info.descent + fnt_info.leading)
  322.     {
  323.         charwid_pix = fnt_info.widMax;
  324.         rowheight_pix = fnt_info.ascent + fnt_info.descent + fnt_info.leading;
  325.         SizeWindow(the_windo, X_PIX_WIN, Y_PIX_WIN, TRUE);
  326.     }
  327.  
  328.     /* Could check if bold-condense is same size as normal to allow/dissallow bold mode? */
  329.     ShowWindow(the_windo);
  330. }
  331.  
  332. /********
  333. **
  334. **    maccur_init_menus:  Set up menu bar (for now, only the apple menu).
  335. **
  336. **
  337. ********/
  338.  
  339. static void maccur_init_menus(void)
  340. {
  341.     Handle menu_bar_hndl;
  342.     MenuHandle menu_hndl;
  343.     char about_str[128];
  344.  
  345.     if ((menu_bar_hndl = GetNewMBar(MENU_RES_ID)) != NULL)
  346.     {
  347.         SetMenuBar(menu_bar_hndl);
  348.         menu_hndl = GetMHandle(MENU_RES_ID);
  349.         if (_maccur_about_res_id != 0)
  350.         {
  351.             sprintf(about_str, "About %s...", _maccur_pgm_name);
  352.             SetItem(menu_hndl, 1, CtoPstr(about_str));
  353.             maccur_about_mitm = 1;
  354.         }
  355.         else
  356.         {
  357.             DelMenuItem(menu_hndl, 1);
  358.             maccur_about_mitm = 0;
  359.         }
  360.         AddResMenu(menu_hndl, 'DRVR');
  361.  
  362.         DrawMenuBar();
  363.         maccur_has_menu = TRUE;
  364.     }
  365.     else maccur_has_menu = FALSE;
  366. }
  367.  
  368. /********
  369. **
  370. **    maccur_draw_text_line:  Write a single line of text to window.  Input text is
  371. **        type chtype, with attribute info.
  372. **
  373. **
  374. ********/
  375.  
  376. static void maccur_draw_text_line(
  377. chtype *line_ptr,        /* -R- Pointer to text to write. */
  378. int n,                    /* -R- Number of characters. */
  379. int row,                /* -R- Start at what row on screen (first row is 0). */
  380. int col                    /* -R- Start at what column on screen (first col is 0). */
  381. ) {
  382.     int i, first_pass_flag, j, attr, previous_attr, txt_face;
  383.     char out_str[MAX_OUT_STRSEG];
  384.  
  385.     SetPort(the_windo);
  386.  
  387.     MoveTo(COL_TO_PIX(col), ROW_TO_PIX(row));
  388.  
  389.     for (i = 0, first_pass_flag = TRUE; i < n; )                        /* Loop until string is written, writing it in segments */
  390.     {                                                                    /*   that all have the same attribute. */
  391.         for (j = 0, attr = (*(line_ptr + i) & A_ATTRIBUTES);
  392.                 i < n && j < MAX_OUT_STRSEG && attr == (*(line_ptr + i) & A_ATTRIBUTES);
  393.                 i++, j++)
  394.             out_str[j] = (*(line_ptr + i) & A_CHARTEXT);
  395.  
  396.         if (attr != previous_attr || first_pass_flag)                    /* Determine/set attribute for this segment... */
  397.         {
  398.             if (attr & A_REVERSE || attr & A_STANDOUT)                    /* Should do standout w/ hilite? */
  399.                 TextMode(notSrcCopy);
  400.             else
  401.                 TextMode(srcCopy);
  402.  
  403.             txt_face = normal;
  404.             if (attr & A_UNDERLINE)
  405.                 txt_face |= underline;
  406.  
  407.             if (attr & A_BOLD)                                            /* It is assument that bold condense is same size as normal. */
  408.                 txt_face |= (bold | condense);
  409.  
  410.             TextFace(txt_face);
  411.             previous_attr = attr;
  412.         }
  413.         DrawText(out_str, 0, j);
  414.         first_pass_flag = FALSE;
  415.     }
  416. }
  417.  
  418. /********
  419. **
  420. **    maccur_flash_cursor:  Flash cursor.
  421. **
  422. **
  423. ********/
  424.  
  425. static void maccur_flash_cursor(void)
  426. {
  427.     InvertRect(&cursor_rect);
  428.     cursor_inverted = !cursor_inverted;
  429. }
  430.  
  431. /********
  432. **
  433. **    maccur_unflash_cursor:  Unhighlight cursor if it is highlighted.
  434. **
  435. **
  436. ********/
  437.  
  438. static void maccur_unflash_cursor(void)
  439. {
  440.     if (cursor_inverted) maccur_flash_cursor();
  441. }
  442.  
  443. /********
  444. **
  445. **    maccur_set_cursor:  Set cursor_rect to reflect current cursor position.
  446. **        Before moving it, un-invert it if necessary (based on cursor_inverted flag).
  447. **
  448. **
  449. ********/
  450.  
  451. static void maccur_set_cursor(
  452. int row,        /* -R- Row for cursor. */
  453. int col            /* -R- Column for cursor. */
  454. ) {
  455.  
  456.     if (cursor_inverted) maccur_flash_cursor();
  457.     show_cursor_flag = TRUE;
  458.  
  459.     row = MIN(row, _maccur_lines - 1);
  460.     col = MIN(col, _maccur_cols - 1);
  461.  
  462.     cursor_rect.bottom = ROW_TO_PIX(row) + fnt_info.descent + fnt_info.leading;
  463.     cursor_rect.right = COL_TO_PIX(col + 1);
  464.     cursor_rect.top = cursor_rect.bottom - rowheight_pix;
  465.     cursor_rect.left = COL_TO_PIX(col);
  466.  
  467. }
  468.  
  469. /********
  470. **
  471. **    maccur_mouse_down_evnt:  Do something about mouse down event.  All that
  472. **        is handled is the apple menu, dragging the window, and system clicks.
  473. **
  474. **
  475. ********/
  476.  
  477. static void maccur_mouse_down_evnt(
  478. EventRecord *event_ptr        /* -R- The event details. */
  479. ) {
  480.     WindowPtr wndo_ptr;
  481.     MenuHandle apl_menu_hndl;
  482.     Str255 nam;
  483.     long menu_choice;
  484.     short wnd_part, menu_id, menu_itm, num;
  485.  
  486.     wnd_part = FindWindow(event_ptr->where, &wndo_ptr);
  487.     switch (wnd_part)
  488.     {
  489.         case inMenuBar:
  490.             if ((menu_choice = MenuSelect(event_ptr->where)) != 0)
  491.             {
  492.                 menu_id = HiWord(menu_choice);
  493.                 menu_itm = LoWord(menu_choice);
  494.  
  495.                 if (menu_id == MENU_RES_ID)
  496.                 {
  497.                     if (menu_itm == maccur_about_mitm)                    /* See if this is about... */
  498.                     {
  499.                         if (NoteAlert(_maccur_about_res_id, NULL) == -1)
  500.                             SysBeep(1);
  501.                     }
  502.                     else
  503.                     {
  504.                         apl_menu_hndl = GetMHandle(MENU_RES_ID);        /* If not, pass it on. */
  505.                         GetItem(apl_menu_hndl, menu_itm, nam);
  506.                         num = OpenDeskAcc(nam);
  507.                     }
  508.                 }
  509.                 HiliteMenu(0);
  510.             }
  511.             break;
  512.  
  513.         case inSysWindow:
  514.             SystemClick(event_ptr, wndo_ptr);
  515.             break;
  516.  
  517.         case inContent:
  518.             break;
  519.  
  520.         case inDrag:
  521.             DragWindow(wndo_ptr, event_ptr->where,
  522.                                 &screenBits.bounds);
  523.             break;
  524.     }
  525. }
  526.  
  527. /********
  528. **
  529. **    maccur_event_loop: Main event loop.  Argument indicates whether it is to
  530. **        return due to a null event or due to a key stroke.
  531. **
  532. **    Returns:
  533. **        Reason for return (null or keystroke).
  534. **
  535. **
  536. ********/
  537.  
  538. static int maccur_event_loop(
  539. int until_flags
  540. ) {
  541.     EventRecord event;
  542.     int i;
  543.     long sleep;
  544.     char c;
  545.  
  546.     if (TST_BIT(until_flags, MACCUR_RETURN_ON_CHAR_BIT))                /* If waiting for a character, don't need a lot of CPU. */
  547.     {
  548.         if (in_background_flag)                                            /* Don't need any in background. */
  549.             sleep = LONG_MAX;
  550.         else sleep = FLASH_TICKS;                                        /* Just need enough to flash cursor in foreground. */
  551.     }
  552.     else                                                                /* If not waiting for a character, try to give up some time. */
  553.     {                                                                    /*   but maybe not a lot. */
  554.         if (in_background_flag)
  555.             sleep = _maccur_bg_sleep_ticks;
  556.         else sleep = _maccur_fg_sleep_ticks;
  557.     }
  558.  
  559.     while (1)                                                            /* Loop until return condition is met. */
  560.     {
  561.         if (WaitNextEvent(everyEvent, &event, sleep, nil))
  562.         {
  563.             switch (event.what)
  564.             {
  565.                 case kHighLevelEvent:
  566.                     AEProcessAppleEvent(&event);
  567.                     break;
  568.  
  569.                 case mouseDown:
  570.                     if (maccur_has_menu)
  571.                         maccur_mouse_down_evnt(&event);
  572.                     break;
  573.  
  574.                 case keyDown:
  575.                 case autoKey:
  576.                     if ((event.modifiers & cmdKey) != 0)                /* Ignore all command keys except CMD-. */
  577.                     {
  578.                         if ((event.message & charCodeMask) == '.')        /* This may exit right away or simulate a control-C interrupt. */
  579.                         {
  580.                             switch (_maccur_handle_break_option)
  581.                             {
  582.                                 case MACCUR_EXIT_ON_BREAK:
  583.                                     ExitToShell();
  584.                                     break;
  585.  
  586.                                 case MACCUR_SIGNAL_BREAK:
  587.                                     raise(SIGINT);
  588.                                     break;
  589.                             }
  590.                         }
  591.                         else break;
  592.                     }
  593.  
  594.                     if (typeahead_cnt >= MAX_TYPEAHEAD)                    /* Other keystrokes go into typeahead (if there is room). */
  595.                         SysBeep(1);                                        /* Typeahead buf is circular. */
  596.                     else
  597.                     {
  598.                         typebuf[typeahead_indx % MAX_TYPEAHEAD].msg = event.message;
  599.                         typebuf[typeahead_indx % MAX_TYPEAHEAD].mod = event.modifiers;
  600.                     }
  601.                     typeahead_indx++;
  602.                     typeahead_cnt++;
  603.  
  604.                     if (TST_BIT(until_flags, MACCUR_RETURN_ON_CHAR_BIT))/* Return if keystroke was what was wanted. */
  605.                         return MACCUR_RETURN_ON_CHAR_BIT;
  606.                     break;
  607.  
  608.                 case updateEvt:
  609.                     BeginUpdate((WindowPtr)(event.message));
  610.  
  611.                     EraseRect(&cursor_rect);                            /* This may be unnecessary??? */
  612.                     for (i = 0; i < _maccur_lines; i++)                    /* Redraw the screen. */
  613.                         maccur_draw_text_line(screen_char_arry + i * _maccur_cols,
  614.                                             _maccur_cols, i, 0);
  615.                     cursor_inverted = FALSE;
  616.  
  617.                     EndUpdate((WindowPtr)(event.message));
  618.                     break;
  619.  
  620.                 case osEvt:                                                /* Switch background/foreground. */
  621.                     if ((event.message & suspendResumeMessage) == resumeFlag)
  622.                         in_background_flag = FALSE;
  623.                     else
  624.                     {
  625.                         in_background_flag = TRUE;
  626.                         maccur_unflash_cursor();                        /* Turn cursor off in the background. */
  627.                     }
  628.                     break;
  629.  
  630.             }
  631.         }
  632.         else if (TST_BIT(until_flags, MACCUR_RETURN_ON_IDLE_BIT))        /* If just letting CPU run, this is the cue to split. */
  633.             return MACCUR_RETURN_ON_IDLE_BIT;
  634.  
  635.         if (!in_background_flag && show_cursor_flag &&                    /* See if its time to flash the cursor. */
  636.                 event.when - last_flash_when > FLASH_TICKS)
  637.         {
  638.             if (event.what != osEvt)
  639.                 maccur_flash_cursor();
  640.             last_flash_when = event.when;
  641.         }
  642.     }
  643. }
  644.  
  645. /****
  646. * The following "keypad map" maps various non-ascii keystrokes to
  647. * their curses KEY_xxx equivalents.  This could be made global so
  648. * that user supplied replacements could be linked in (but who would
  649. * want to go to all that trouble).
  650. ****/
  651.  
  652. #define KEYMAP_BASE 0x33                                                /* Key number of first key to translate. */
  653. #define KEYMAP_TOP (KEYMAP_BASE + sizeof(dflt_keypad_map)/sizeof(KEYPAD_MAP))
  654. #define KEYMAP_NOCODE 0                                                    /* If this is key translation, return ascii code for that key. */
  655.  
  656. typedef struct keypad_map_strct {    /* Determine what to do with key/modifier: */
  657.     chtype basic_code;                /* This is translation of unmodified key. */
  658.     chtype shift_code;                /* Translation of key with shift. */
  659.     chtype opt_code;                /* Translation of key with option. */
  660.     chtype shift_opt_code;            /* Translation of key with shift-option. */
  661. } KEYPAD_MAP;
  662.  
  663. static KEYPAD_MAP dflt_keypad_map[] = {
  664. /* 33 delete */        {KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE},
  665. /* 34 */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  666. /* 35 */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  667. /* 36 */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  668. /* 37 */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  669. /* 38 */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  670. /* 39 */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  671. /* 3A */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  672. /* 3B */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  673. /* 3C */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  674. /* 3D */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  675. /* 3E */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  676. /* 3F */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  677. /* 40 */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  678. /* 41 KP-. */        {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  679. /* 42 rt arrow (Mac +) */    {KEY_RIGHT, KEY_SRIGHT, KEYMAP_NOCODE, KEYMAP_NOCODE},
  680. /* 43 KP-* */        {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  681. /* 44 */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  682. /* 45 KP-+ */        {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  683. /* 46 left arrow (Mac +) */    {KEY_LEFT, KEY_SLEFT, KEYMAP_NOCODE, KEYMAP_NOCODE},
  684. /* 47 clear */        {KEY_CLEAR, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  685. /* 48 down arrow (Mac +) */    {KEY_DOWN, KEY_NPAGE, KEY_END, KEYMAP_NOCODE},
  686. /* 49 */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  687. /* 4A */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  688. /* 4B KP-/ */        {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  689. /* 4C enter */        {KEY_ENTER, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  690. /* 4D up arrow (Mac +) */    {KEY_UP, KEY_PPAGE, KEY_HOME, KEYMAP_NOCODE},
  691. /* 4E KP-- */        {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  692. /* 4F */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  693. /* 50 */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  694. /* 51 KP-= */        {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  695. /* 52 KP-0 */        {KEYMAP_NOCODE, KEYMAP_NOCODE, KEY_F(0), KEY_F(10)},
  696. /* 53 KP-1 */        {KEY_C1, KEYMAP_NOCODE, KEY_F(1), KEY_F(11)},
  697. /* 54 KP-2 */        {KEY_DOWN, KEYMAP_NOCODE, KEY_F(2), KEY_F(12)},
  698. /* 55 KP-3 */        {KEY_C3, KEYMAP_NOCODE, KEY_F(3), KEY_F(13)},
  699. /* 56 KP-4 */        {KEY_LEFT, KEYMAP_NOCODE, KEY_F(4), KEY_F(14)},
  700. /* 57 KP-5 */        {KEY_B2, KEYMAP_NOCODE, KEY_F(5), KEY_F(15)},
  701. /* 58 KP-6 */        {KEY_RIGHT, KEYMAP_NOCODE, KEY_F(6), KEY_F(16)},
  702. /* 59 KP-7 */        {KEY_A1, KEYMAP_NOCODE, KEY_F(7), KEY_F(17)},
  703. /* 5A */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  704. /* 5B KP-8 */        {KEY_UP, KEYMAP_NOCODE, KEY_F(8), KEY_F(18)},
  705. /* 5C KP-9 */        {KEY_A3, KEYMAP_NOCODE, KEY_F(9), KEY_F(19)},
  706. /* 5D */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  707. /* 5E */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  708. /* 5F */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  709. /* 60 F5 */            {KEY_F(5), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  710. /* 61 F6 */            {KEY_F(6), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  711. /* 62 F7 */            {KEY_F(7), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  712. /* 63 F3 */            {KEY_F(3), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  713. /* 64 F8 */            {KEY_F(8), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  714. /* 65 F9 */            {KEY_F(9), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  715. /* 66 */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  716. /* 67 F11 */        {KEY_F(11), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  717. /* 68 */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  718. /* 69 F13 */        {KEY_F(13), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  719. /* 6A */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  720. /* 6B F14 */        {KEY_F(14), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  721. /* 6C */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  722. /* 6D F10 */        {KEY_F(10), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  723. /* 6E */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  724. /* 6F F12 */        {KEY_F(12), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  725. /* 70 */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  726. /* 71 F15 */        {KEY_F(15), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  727. /* 72 ins */        {KEY_IC, KEY_IL, KEYMAP_NOCODE, KEYMAP_NOCODE},
  728. /* 73 home */        {KEY_HOME, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  729. /* 74 pgup */        {KEY_PPAGE, KEY_SR, KEYMAP_NOCODE, KEYMAP_NOCODE},
  730. /* 75 fwd del */    {KEY_DC, KEY_DL, KEYMAP_NOCODE, KEYMAP_NOCODE},
  731. /* 76 F4 */            {KEY_F(4), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  732. /* 77 end */        {KEY_END, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  733. /* 78 F2 */            {KEY_F(2), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  734. /* 79 pgdn */        {KEY_NPAGE, KEY_SF, KEYMAP_NOCODE, KEYMAP_NOCODE},
  735. /* 7A F1 */            {KEY_F(1), KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE},
  736. /* 7B left arrow */    {KEY_LEFT, KEY_SLEFT, KEYMAP_NOCODE, KEYMAP_NOCODE},
  737. /* 7C rt arrow */    {KEY_RIGHT, KEY_SRIGHT, KEYMAP_NOCODE, KEYMAP_NOCODE},
  738. /* 7D down arrow */    {KEY_DOWN, KEY_NPAGE, KEY_END, KEYMAP_NOCODE},
  739. /* 7E up arrow */    {KEY_UP, KEY_PPAGE, KEY_HOME, KEYMAP_NOCODE},
  740. /* 7F */            {KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE, KEYMAP_NOCODE}
  741. };
  742.  
  743. /********
  744. **
  745. **    maccur_key_trans:  Return curses key code based on keystroke event.
  746. **        If key has no entry in translation table, or entry is KEYMAP_NOCODE,
  747. **        return ascii value.
  748. **
  749. **    Returns:
  750. **        Character translation of keystroke (type chtype).
  751. **
  752. **
  753. ********/
  754.  
  755. static chtype maccur_key_trans(
  756. KEY_EVENT *ch_evnt_ptr,
  757. int keypad_enabled_flag
  758. ) {
  759.     chtype c, c_ascii, key;
  760.  
  761.     c_ascii = ch_evnt_ptr->msg & charCodeMask;
  762.     key = (ch_evnt_ptr->msg & keyCodeMask) >> 8;
  763.  
  764.     if (keypad_enabled_flag && key >= KEYMAP_BASE && key < KEYMAP_TOP)
  765.     {
  766.         if ((ch_evnt_ptr->mod & shiftKey) && (ch_evnt_ptr->mod & optionKey))
  767.             c = (dflt_keypad_map + (key - KEYMAP_BASE))->shift_opt_code;
  768.         else if ((ch_evnt_ptr->mod & shiftKey))
  769.             c = (dflt_keypad_map + (key - KEYMAP_BASE))->shift_code;
  770.         else if ((ch_evnt_ptr->mod & optionKey))
  771.             c = (dflt_keypad_map + (key - KEYMAP_BASE))->opt_code;
  772.         else
  773.             c = (dflt_keypad_map + (key - KEYMAP_BASE))->basic_code;
  774.  
  775.         if (c == KEYMAP_NOCODE) c = c_ascii;
  776.     }
  777.     else
  778.     {
  779.         if (key == 0x4C) c = '\n';                                        /* Give the keypad enter key a better ascii translation. */
  780.         else c = c_ascii;
  781.     }
  782.  
  783.     return c;
  784. }
  785.  
  786. /********
  787. **
  788. **    maccur_flush_typeahead:  Flush the typeahead buffer.
  789. **
  790. **
  791. ********/
  792.  
  793. void maccur_flush_typeahead(
  794. void
  795. ) {
  796.  
  797.     typeahead_indx = typeahead_cnt = outchar_indx = 0;
  798. }
  799.  
  800. /********
  801. **
  802. **    maccur_init: Entry point for initalization.  Sets LINES and COLS
  803. **        to the size of the window that is opened up.
  804. **
  805. **    Returns:
  806. **        TRUE if initialization is successful, else FALSE.
  807. **
  808. **
  809. ********/
  810.  
  811. bool maccur_init(void)
  812. {
  813.     int i, screen_chars;
  814.  
  815.     screen_chars = _maccur_cols * _maccur_lines;
  816.     if (screen_char_arry == NULL)                                        /* Allow for multiple calls to this routine (especially */
  817.     {                                                                    /*   implicit ones for fake stdio). */
  818.         maccur_init_toolbox();
  819.         maccur_init_event();
  820.         maccur_init_window();
  821.         maccur_init_menus();
  822.  
  823.         LINES = _maccur_lines;
  824.         COLS = _maccur_cols;
  825.  
  826.         if ((screen_char_arry = malloc(screen_chars * sizeof(chtype))) == NULL)
  827.             return FALSE;
  828.     }
  829.  
  830.     for (i = 0; i < screen_chars; i++)                                    /* Blank the screen. */
  831.         *(screen_char_arry + i) = ' ';
  832.  
  833.     return TRUE;
  834. }
  835.  
  836. /********
  837. **
  838. **    maccur_refresh: Refresh the screen for a curses window.
  839. **
  840. **    Returns:
  841. **        ERR on error, else OK.
  842. **
  843. **
  844. ********/
  845.  
  846. int maccur_refresh(WINDOW *win, bool outflag)
  847. {
  848.     static int    next_cursor_col = 0;        /* Save cursor position for next window refresh. */
  849.     static int    next_cursor_row = 0;        /*   (in case there are multiple calls before refresh and some have leaveok TRUE). */
  850.     static int window_current_flag;            /* Set to true when window is updated from saved image. */
  851.     static int cursor_enabled_flag;            /* Set to true if at least one window contributing to screen has a cursor. */
  852.     int i, mov_size, maxx, maxy;
  853.     chtype *src_ptr, *dst_ptr;
  854.                                                                         /* Your comment here                                       */
  855.  
  856.     if (screen_char_arry == NULL) return ERR;                            /* Initialization has not been done (bad). */
  857.  
  858.     if (win)                                                            /* If window was passed, transfer chars from it. */
  859.     {
  860.         if (win->_begy < _maccur_lines && win->_begx < _maccur_cols)
  861.         {
  862.             dst_ptr = screen_char_arry + (win->_begy * _maccur_cols) +
  863.                                 win->_begx;
  864.             if (win->_flags & _ISPAD)
  865.             {
  866.                 maxx = win->_pmap_maxx - win->_pmap_orgx;                /* For pads, get # rows and columns to display. */
  867.                 maxy = win->_pmap_maxy - win->_pmap_orgy;
  868.                 src_ptr = win->_y +                                        /* Point to 1st displayed character in pad. */
  869.                                 ((win->_pmap_orgy * win->_xdim) +
  870.                                 win->_pmap_orgx);
  871.             }
  872.             else
  873.             {
  874.                 maxx = win->_maxx;
  875.                 maxy = win->_maxy;
  876.                 src_ptr = win->_y;
  877.             }
  878.             mov_size = MIN(maxx, _maccur_cols - win->_begx) *
  879.                                 sizeof(chtype);
  880.             for (i = 0; i < maxy && i + win->_begy < _maccur_lines;        /* Copy text from window to screen image. */
  881.                                 i++, dst_ptr += _maccur_cols,
  882.                                     src_ptr += win->_xdim)
  883.                 memcpy(dst_ptr, src_ptr, mov_size); 
  884.         }
  885.  
  886.         if (!win->_leave)                                                /* If cursor is not left off, */
  887.         {
  888.             next_cursor_row = _CURS_CURSOR_SCREEN_ROW(win);                /* Save its position. */
  889.             next_cursor_col = _CURS_CURSOR_SCREEN_COL(win);
  890.             cursor_enabled_flag = TRUE;                                    /* It will be enabled on next screen update. */
  891.         }
  892.         else if (window_current_flag)                                    /* If this is 1st refresh after update and cursor */
  893.             cursor_enabled_flag = FALSE;                                /*   disabled, indicate that.  Subsequent refreshes */
  894.         else cursor_enabled_flag = cursor_enabled_flag || FALSE;        /*   or into flag so if cursor is enabled once it is shown. */
  895.         window_current_flag = FALSE;
  896.     }
  897.  
  898.     if (outflag)                                                        /* If actual screen update is to be done... */
  899.     {
  900.         for (i = 0; i < _maccur_lines; i++)                                /* Draw the characters. */
  901.             maccur_draw_text_line(screen_char_arry + i * _maccur_cols,
  902.                                 _maccur_cols, i, 0);
  903.         if (cursor_enabled_flag)
  904.         {
  905.             cursor_inverted = FALSE;                                    /* Window was completely re-written, so cursor is gone. */
  906.             maccur_set_cursor(next_cursor_row, next_cursor_col);
  907.         }
  908.         else show_cursor_flag = FALSE;
  909.         window_current_flag = TRUE;
  910.     }
  911.  
  912.     return OK;
  913. }
  914.  
  915. /********
  916. **
  917. **    maccur_end:  Exit curses mode.
  918. **
  919. **    Returns:
  920. **        OK.
  921. **
  922. **
  923. ********/
  924.  
  925. bool maccur_end(void)
  926. {
  927.     void maccur_noncurse_mode_scroll();
  928.  
  929.     maccur_noncurse_mode_scroll();                                        /* Scroll screen up a line and position cursor at bottom. */
  930.  
  931.     direct_curs_pos_row = _maccur_lines - 1;
  932.     direct_curs_pos_col = 0;
  933.  
  934.     maccur_set_cursor(direct_curs_pos_row, direct_curs_pos_col);
  935.     return OK;
  936. }
  937.  
  938. /********
  939. **
  940. **    maccur_beep: Beep or flash the screen.
  941. **
  942. **
  943. ********/
  944.  
  945. void maccur_beep(
  946. int flash_flag        /* -R- TRUE to flash instead of beep. */
  947. ) {
  948.     if (flash_flag)
  949.         SysBeep(0);
  950.     else
  951.         SysBeep(1);
  952. }
  953.  
  954. /********
  955. **
  956. **    maccur_kbinp: Take a single character input.
  957. **
  958. **    Returns:
  959. **        Character read, or ERR if no character ready or error.
  960. **
  961. **
  962. ********/
  963.  
  964. int maccur_kbinp(WINDOW *win, bool raw, bool cbreak)
  965. {
  966.  
  967.     if (typeahead_cnt == 0 && win->_nodelay)                            /* If caller is in a hurry don't make 'em wait */
  968.         return ERR;
  969.  
  970.     if (typeahead_cnt == 0)                                                /* If need to wait for input... */
  971.     {
  972.         maccur_set_cursor(_CURS_CURSOR_SCREEN_ROW(win),                    /* Set cursor to current input position. */
  973.                                 _CURS_CURSOR_SCREEN_COL(win));            /*   (this will also un-invert it). */
  974.         if (win->_leave)                                                /* If cursor is to be left off, set flag to false. */
  975.             show_cursor_flag = FALSE;
  976.         maccur_event_loop(SET_BIT(MACCUR_RETURN_ON_CHAR_BIT));
  977.     }
  978.  
  979.     if (typeahead_cnt > 0)                                                /* There should be something to return now, so do it... */
  980.     {
  981.         typeahead_cnt--;
  982.         if (outchar_indx >= MAX_TYPEAHEAD) outchar_indx = 0;
  983.         return maccur_key_trans(typebuf + outchar_indx++, win->_use_keypad);
  984.     }
  985.  
  986.     return ERR;
  987. }
  988.  
  989. /********
  990. **
  991. **    maccur_alert_text:  Display a string in an alert box.
  992. **        Trim white space and newlines from beginning and end of string first.
  993. **
  994. **
  995. ********/
  996.  
  997. static void maccur_alert_text(
  998. char *txt
  999. ) {
  1000.     static char buf[256];
  1001.     int len;
  1002.  
  1003.     while (isspace(*txt))                                                /* Strip off leading white space. */
  1004.         txt++;
  1005.     len = strlen(txt);
  1006.  
  1007.     while (len > 0 && isspace(*(txt + len - 1)))                        /* Strip off trailing white space. */
  1008.         len--;
  1009.     if (len > 255) len = 255;
  1010.  
  1011.     buf[0] = len;                                                        /* Make it a pascal string. */
  1012.     memcpy(buf + 1, txt, len);
  1013.  
  1014.     ParamText((ConstStr255Param) buf, NULL, NULL, NULL);
  1015.  
  1016.     Alert(ALERT_RSRC_ID, NULL);                                            /* Display as an alert. */
  1017. }
  1018.  
  1019. /********
  1020. **
  1021. **    maccur_alert_msg:  Display a string as an alert message, after
  1022. **        formatting it with sprintf.
  1023. **
  1024. **
  1025. ********/
  1026.  
  1027. void maccur_alert_msg(
  1028. char *fmt,
  1029. ...
  1030. ) {
  1031.     va_list args;
  1032.     int rtn;
  1033.  
  1034.     if (screen_char_arry == NULL)
  1035.         maccur_init();
  1036.  
  1037.     va_start(args, fmt);
  1038.     rtn = vsprintf(_curses_prntw, fmt, args);
  1039.     va_end(args);
  1040.  
  1041.     if (rtn < 0) strcpy(_curses_prntw, "Error in curses");
  1042.  
  1043.     maccur_alert_text(_curses_prntw);
  1044. }
  1045.  
  1046. /********
  1047. **
  1048. **    maccur_cpu_share:  Call the event manager so CPU time can be shared.
  1049. **
  1050. **
  1051. ********/
  1052.  
  1053. void maccur_cpu_share(void)
  1054. {
  1055.     maccur_event_loop(SET_BIT(MACCUR_RETURN_ON_IDLE_BIT));
  1056. }
  1057.  
  1058.  
  1059. /*    **************************************************************************    */
  1060. /*                                    STDIO emulation                                */
  1061. /*                                                                                */
  1062. /*    The following routines can be used to emulate standard io calls to stdin    */
  1063. /*    and stdout, placing the output in the curses window.                        */
  1064. /*                                                                                */
  1065. /*    **************************************************************************    */
  1066.  
  1067.  
  1068. /********
  1069. **
  1070. **    maccur_noncurse_mode_scroll: Scroll the screen up a line.
  1071. **
  1072. **
  1073. ********/
  1074.  
  1075. static void maccur_noncurse_mode_scroll(void)
  1076. {
  1077.     int i;
  1078.     chtype *scrn_ptr;
  1079.  
  1080.     memmove(screen_char_arry, screen_char_arry + _maccur_cols,                    /* Scroll it up. */
  1081.                                 _maccur_cols * (_maccur_lines - 1) * sizeof(chtype));
  1082.     scrn_ptr = screen_char_arry + ((_maccur_lines - 1) * _maccur_cols);
  1083.     for (i = 0; i < _maccur_cols; i++)                                            /* Clear bottom line. */
  1084.         *(scrn_ptr + i) = ' ';
  1085.  
  1086.     for (i = 0; i < _maccur_lines; i++)
  1087.         maccur_draw_text_line(screen_char_arry + i * _maccur_cols,
  1088.                                 _maccur_cols, i, 0);
  1089.     cursor_inverted = FALSE;
  1090. }
  1091.  
  1092. /********
  1093. **
  1094. **    maccur_noncurse_mode_show_str:  Display a string on the screen.
  1095. **        Wrap strings that are too long and expand tabs.
  1096. **
  1097. **
  1098. ********/
  1099.  
  1100. static void maccur_noncurse_mode_show_str(
  1101. char *str,                    /* -R- String to display. */
  1102. int *row_pos_ptr,            /* -M- Passed as row to start string, updated to row of end of string. */
  1103. int *col_pos_ptr,            /* -M- Passed as column to start string, updated to column of end of string. */
  1104. int *scroll_cnt_ptr,        /* -W- Return number of lines up the screen was scrolled. */
  1105. bool show_str_flag,            /* -R- TRUE to display string, FALSE to just return cursor position at end of string. */
  1106. bool add_newline_flag,        /* -R- True if extra newline should be added after string is displayed. */
  1107. bool clear_to_eos_flag        /* -R- True to clear all of screen following displayed string. */
  1108. ) {
  1109.     int nchars, char_pos, row_pos, col_pos, i, n_to_show,
  1110.         end_col_pos, move_down_flag;
  1111.     chtype *scrn_ptr;
  1112.     char *out_ptr, *cp;
  1113.  
  1114.     if (scroll_cnt_ptr != NULL)
  1115.         *scroll_cnt_ptr = 0;
  1116.     nchars = strlen(str);
  1117.     char_pos = 0;
  1118.     row_pos = *row_pos_ptr;
  1119.     col_pos = *col_pos_ptr;
  1120.     out_ptr = str;
  1121.  
  1122.     while (nchars > 0)                                                    /* Loop while there are characters to write out. */
  1123.     {
  1124.         if (col_pos >= _maccur_cols)
  1125.         {
  1126.             col_pos = 0;
  1127.             row_pos++;
  1128.         }
  1129.  
  1130.         if (show_str_flag && row_pos >= _maccur_lines)                    /* If writing position is past end of screen, scroll. */
  1131.         {
  1132.             maccur_noncurse_mode_scroll();
  1133.             if (scroll_cnt_ptr != NULL) (*scroll_cnt_ptr)++;
  1134.             row_pos = _maccur_lines - 1;
  1135.         }
  1136.  
  1137.         n_to_show = MIN(_maccur_cols - col_pos, nchars);                /* Determine how many chars to put in this line: */
  1138.         if ((cp = strchr(out_ptr, '\n')) != NULL)                        /*   up to end of line, up to end of string, */
  1139.             n_to_show = MIN(n_to_show, cp - out_ptr);                    /*   up to next newline, or up to tab. */
  1140.         if ((cp = strchr(out_ptr, '\t')) != NULL)
  1141.             n_to_show = MIN(n_to_show, cp - out_ptr);
  1142.  
  1143.         if (show_str_flag)
  1144.         {
  1145.             scrn_ptr = screen_char_arry + (row_pos * _maccur_cols) +
  1146.                                 col_pos;
  1147.             for (i = 0; i < n_to_show; i++)                                /* Copy the characters out. */
  1148.                 *(scrn_ptr + i) = *(out_ptr + i);
  1149.         }
  1150.         col_pos += n_to_show;
  1151.  
  1152.         move_down_flag = FALSE;
  1153.         if (*(out_ptr + n_to_show) == '\n')                                /* If newline encountered, blank out rest of line */
  1154.         {                                                                /*   and position to beginning of next. */
  1155.             if (show_str_flag)
  1156.             {
  1157.                 scrn_ptr = screen_char_arry + (row_pos * _maccur_cols);
  1158.                 while (col_pos < _maccur_cols)
  1159.                     *(scrn_ptr + col_pos++) = ' ';
  1160.             }
  1161.             n_to_show++;                                                /* Skip over the '\n' */
  1162.             move_down_flag = TRUE;
  1163.         }
  1164.         else if (*(out_ptr + n_to_show) == '\t')                        /* For a tab, blank up to the next tab stop. */
  1165.         {
  1166.             end_col_pos = col_pos + (_curses_tab_wid -                    /* Blank fwd until col_pos becomes multiple of tab wid. */
  1167.                                 col_pos % _curses_tab_wid);
  1168.             end_col_pos = MIN(end_col_pos, _maccur_cols);                /* But don't wrap over into next line. */
  1169.             if (show_str_flag)
  1170.             {
  1171.                 scrn_ptr = screen_char_arry + (row_pos * _maccur_cols);
  1172.                 while (col_pos < end_col_pos)
  1173.                     *(scrn_ptr + col_pos++) = ' ';
  1174.             }
  1175.             col_pos = end_col_pos;
  1176.             n_to_show++;                                                /* Skip over the '\t' */
  1177.         }
  1178.  
  1179.         if (show_str_flag)
  1180.             maccur_draw_text_line(screen_char_arry +                    /* Redraw the modified line. */
  1181.                                 row_pos * _maccur_cols,
  1182.                                 _maccur_cols, row_pos, 0);
  1183.  
  1184.         if (move_down_flag)
  1185.         {
  1186.             col_pos = 0;                                                /* Move to next line. */
  1187.             row_pos++;
  1188.         }
  1189.  
  1190.         if (show_str_flag && row_pos >= _maccur_lines)                    /* If writing position is past end of screen, scroll. */
  1191.         {
  1192.             maccur_noncurse_mode_scroll();
  1193.             if (scroll_cnt_ptr != NULL) (*scroll_cnt_ptr)++;
  1194.             row_pos = _maccur_lines - 1;
  1195.         }
  1196.  
  1197.         out_ptr += n_to_show;
  1198.         nchars -= n_to_show;
  1199.     }
  1200.  
  1201.     if (add_newline_flag || clear_to_eos_flag)                            /* If extra newline is to be added after string output or */
  1202.     {                                                                    /*   or screen is to be cleared up to end of screen. */
  1203.         if (show_str_flag)
  1204.         {
  1205.             int last_row, i_rw;
  1206.  
  1207.             if (clear_to_eos_flag)                                        /* Whether new line or cleareos, will be clearing rest */
  1208.                 last_row = _maccur_lines;                                /*   of current line and possibly others. */
  1209.             else last_row = row_pos + 1;
  1210.  
  1211.             for (i_rw = row_pos; i_rw < last_row; i_rw++)                /* Do next line or a bunch depending on clear_to_eos_flag. */
  1212.             {
  1213.                 scrn_ptr = screen_char_arry + (i_rw * _maccur_cols);
  1214.                 for (i = (i_rw == row_pos ? col_pos : 0);                /* Clear the line. */
  1215.                         i < _maccur_cols; i++)
  1216.                     *(scrn_ptr + i) = ' ';
  1217.  
  1218.                 maccur_draw_text_line(screen_char_arry +                /* Redraw the modified line. */
  1219.                                 i_rw * _maccur_cols,
  1220.                                 _maccur_cols, i_rw, 0);
  1221.             }
  1222.         }
  1223.  
  1224.         if (add_newline_flag)                                            /* If actually echoing a newline. */
  1225.         {
  1226.             col_pos = 0;
  1227.             row_pos++;
  1228.             if (show_str_flag && row_pos >= _maccur_lines)                /* Scroll of necessary. */
  1229.             {
  1230.                 maccur_noncurse_mode_scroll();
  1231.                 if (scroll_cnt_ptr != NULL) (*scroll_cnt_ptr)++;
  1232.                 row_pos = _maccur_lines - 1;
  1233.             }                                                            /* (this automatically clears the last line of screen). */
  1234.         }
  1235.     }
  1236.  
  1237.     *row_pos_ptr = row_pos;
  1238.     *col_pos_ptr = col_pos;
  1239. }
  1240.  
  1241. /********
  1242. **
  1243. **    maccur_noncurse_mode_getstr:  Input a string, echoing input to screen,
  1244. **        allowing editing with left/right arrows, delete key, clear key
  1245. **        (or ctrl-u) to clear input, ctrl-e to move to end of input,
  1246. **        ctrl-d to return EOF.  Special single character mode does away
  1247. **        with most special line editing, and returns with the single char (ala getchar).
  1248. **
  1249. **    Returns:
  1250. **        Number of characters in, or EOF if CTRL-D entered.
  1251. **
  1252. **
  1253. ********/
  1254.  
  1255. static int maccur_noncurse_mode_getstr(
  1256. char *str,                    /* -W- Put the string read here. */
  1257. int max_chars,                /* -R- Size of above string (or -1 if unknown). */
  1258. int single_char_flag        /* -R- True if this is call for a single character. */
  1259. ) {
  1260.     int begin_at, nchars, pos, key, c_ascii, cleareos_flag,
  1261.         redisplay_flag, disp_pos, disp_row, disp_col, scroll_cnt,
  1262.         rtn_val, string_ended_flag, add_newline_flag, save_char;
  1263.  
  1264.     begin_at = (direct_curs_pos_row * _maccur_cols) +                    /* Remember initial cursor position. */
  1265.                                 direct_curs_pos_col;
  1266.  
  1267.     nchars = pos = rtn_val = 0;
  1268.     *str = '\0';
  1269.     string_ended_flag = FALSE;
  1270.     while (!string_ended_flag)
  1271.     {
  1272.         redisplay_flag = FALSE;
  1273.         cleareos_flag = FALSE;
  1274.         add_newline_flag = FALSE;
  1275.  
  1276.         if (typeahead_cnt == 0)                                            /* If need to wait for input... */
  1277.         {
  1278.             disp_row = begin_at/_maccur_cols;
  1279.             disp_col = begin_at % _maccur_cols;
  1280.             save_char = *(str + pos);
  1281.             *(str + pos) = '\0';
  1282.             maccur_noncurse_mode_show_str(str,                            /* Measure string to determine cursor position at */
  1283.                                 &disp_row, &disp_col,                    /*   input point (there might be tabs). */
  1284.                                 NULL, FALSE, FALSE, FALSE);
  1285.             *(str + pos) = save_char;
  1286.  
  1287.             if (disp_col >= _maccur_cols)                                /* Move cursor to next line if it is past end of a line. */
  1288.             {
  1289.                 disp_col = 0;
  1290.                 disp_row++;
  1291.             }
  1292.  
  1293.             if (disp_row >= _maccur_lines)                                /* Scroll if cursor off screen. */
  1294.             {
  1295.                 maccur_noncurse_mode_scroll();
  1296.                 disp_row = _maccur_lines - 1;
  1297.                 begin_at -= _maccur_cols;
  1298.             }
  1299.  
  1300.             maccur_set_cursor(disp_row, disp_col);                        /* Set cursor to current input position. */
  1301.             maccur_event_loop(SET_BIT(MACCUR_RETURN_ON_CHAR_BIT));        /* Get some text. */
  1302.             maccur_unflash_cursor();
  1303.         }
  1304.  
  1305.         if (typeahead_cnt > 0)                                            /* There should be at least one keystroke available. */
  1306.         {
  1307.             typeahead_cnt--;
  1308.             if (outchar_indx >= MAX_TYPEAHEAD) outchar_indx = 0;
  1309.             c_ascii = (typebuf + outchar_indx)->msg & charCodeMask;
  1310.             key = ((typebuf + outchar_indx)->msg & keyCodeMask) >> 8;
  1311.             outchar_indx++;
  1312.  
  1313.             switch (key)                                                /* See if key has special meaning. */
  1314.             {
  1315.                 case 0x7D:                                                /* Up and down arrows (Mac plus and II). */
  1316.                 case 0x7E:                                                /* All ignored. */
  1317.                 case 0x4D:
  1318.                 case 0x48:
  1319.                     SysBeep(1);
  1320.                     break;
  1321.         
  1322.                 case 0x7C:                                                /* Right arrow (Mac II). */
  1323.                 case 0x42:                                                /*   (Mac plus). */
  1324.                     if (pos < nchars)
  1325.                         pos++;
  1326.                     else SysBeep(1);
  1327.  
  1328.                     break;
  1329.         
  1330.                 case 0x7B:                                                /* Left arrow (Mac II). */
  1331.                 case 0x46:                                                /*   (Mac plus). */
  1332.                     if (pos > 0)
  1333.                         pos--;
  1334.                     else SysBeep(1);
  1335.         
  1336.                     break;
  1337.  
  1338.                 case 0x33:                                                /* DELETE key. */
  1339.                     if (pos > 0)
  1340.                     {
  1341.                         if (pos < nchars)
  1342.                             memmove(str + (pos - 1), str + pos, nchars - pos);
  1343.                         *(str + --nchars) = '\0';
  1344.                         pos--;
  1345.                         redisplay_flag = TRUE;
  1346.                         cleareos_flag = TRUE;
  1347.                     }
  1348.                     else SysBeep(1);
  1349.  
  1350.                     break;
  1351.  
  1352.                 case 0x47:                                                /* CLEAR key. */
  1353.                     if (single_char_flag) SysBeep(1);                    /* Don't let getchar user think CLEAR means anything. */
  1354.                     nchars = pos = 0;
  1355.                     *str = '\0';
  1356.                     redisplay_flag = TRUE;
  1357.                     cleareos_flag = TRUE;
  1358.                     break;
  1359.  
  1360.                 case 0x24:                                                /* RETURN key. */
  1361.                 case 0x4C:                                                /* ENTER key. */
  1362.                     if (single_char_flag)                                /* Single character mode will allow \n as a return value. */
  1363.                     {
  1364.                         *str = '\n';
  1365.                         *(str + 1) = '\0';
  1366.                         nchars = 1;
  1367.                     }
  1368.                     else add_newline_flag = TRUE;                        /* Don't return newline in string, so set flag to echo it. */
  1369.                     string_ended_flag = TRUE;
  1370.                     redisplay_flag = TRUE;                                /* Redisplay it to echo newline. */
  1371.                     rtn_val = pos = nchars;
  1372.                     break;
  1373.         
  1374.                 default:
  1375.                     if (c_ascii == 4)                                    /* Control-D (return EOF). */
  1376.                     {
  1377.                         rtn_val = EOF;
  1378.                         string_ended_flag = TRUE;
  1379.                     }
  1380.                     else if (!single_char_flag && c_ascii == 5)            /* Control-E (move to end of input text). */
  1381.                     {
  1382.                         pos = nchars;
  1383.                     }
  1384.                     else if (!single_char_flag && c_ascii == 21)        /* Control-U (same as CLEAR) */
  1385.                     {
  1386.                         nchars = pos = 0;
  1387.                         *str = '\0';
  1388.                         redisplay_flag = TRUE;
  1389.                         cleareos_flag = TRUE;
  1390.                     }
  1391.                     else                                                /* Get here if its just a regular old ascii value. */
  1392.                     {
  1393.                         if (max_chars >= 0 && nchars >= max_chars - 1)
  1394.                             SysBeep(1);
  1395.                         else
  1396.                         {
  1397.                             if (pos < nchars)
  1398.                                 memmove(str + (pos + 1), str + pos, nchars - pos);
  1399.                             *(str + pos++) = c_ascii;
  1400.                             *(str + ++nchars) = '\0';
  1401.                             redisplay_flag = TRUE;
  1402.                         }
  1403.                     }
  1404.                     break;
  1405.             }
  1406.  
  1407.             if (redisplay_flag)                                            /* If something has happened necesitating a redraw, do it. */
  1408.             {
  1409.                 disp_pos = MAX(0, pos - 1);                                /* Just redraw from current position on. */
  1410.                 disp_row = begin_at/_maccur_cols;                        /* But first measure to find start position. */
  1411.                 disp_col = begin_at % _maccur_cols;
  1412.                 save_char = *(str + disp_pos);
  1413.                 *(str + disp_pos) = '\0';
  1414.                 maccur_noncurse_mode_show_str(str,
  1415.                                     &disp_row, &disp_col,
  1416.                                     NULL, FALSE, FALSE, FALSE);
  1417.                 *(str + disp_pos) = save_char;
  1418.  
  1419.                 maccur_noncurse_mode_show_str(str + disp_pos,
  1420.                                 &disp_row, &disp_col,
  1421.                                 &scroll_cnt, TRUE,
  1422.                                 add_newline_flag, cleareos_flag);
  1423.                 begin_at -= scroll_cnt * _maccur_cols;
  1424.             }
  1425.  
  1426.             if (single_char_flag && nchars > 0 && !string_ended_flag)
  1427.             {
  1428.                 string_ended_flag = TRUE;
  1429.                 rtn_val = nchars;
  1430.             }
  1431.         }
  1432.     }
  1433.  
  1434.     direct_curs_pos_row = disp_row;                                        /* Leave cursor where last update put it. */
  1435.     direct_curs_pos_col = disp_col;
  1436.  
  1437.     return rtn_val;
  1438. }
  1439.  
  1440. /********
  1441. **
  1442. **    maccur_printf:  Equivalent to printf.
  1443. **
  1444. **    Returns:
  1445. **        Results of vsprintf.
  1446. **
  1447. **
  1448. ********/
  1449.  
  1450. int    maccur_printf(
  1451. char *fmt,
  1452. ...
  1453. ) {
  1454.     va_list args;
  1455.     int rtn;
  1456.  
  1457.     if (screen_char_arry == NULL)
  1458.         maccur_init();
  1459.  
  1460.     va_start(args, fmt);
  1461.     rtn = vsprintf(_curses_prntw, fmt, args);
  1462.     va_end(args);
  1463.  
  1464.     if (rtn < 0) return rtn;
  1465.  
  1466.     maccur_noncurse_mode_show_str(_curses_prntw, &direct_curs_pos_row,
  1467.                                 &direct_curs_pos_col, NULL, TRUE,
  1468.                                 FALSE, FALSE);
  1469.  
  1470.     if (_maccur_io_sleep_dvsr > 0 && ++cpu_share_rot_cnt >= _maccur_io_sleep_dvsr)
  1471.     {
  1472.         maccur_cpu_share();
  1473.         cpu_share_rot_cnt = 0;
  1474.     }
  1475.  
  1476.     return rtn;
  1477. }
  1478.  
  1479. /********
  1480. **
  1481. **    maccur_puts:  Equivalent to puts.
  1482. **
  1483. **    Returns:
  1484. **        0 (success).
  1485. **
  1486. **
  1487. ********/
  1488.  
  1489. int maccur_puts(
  1490. char *str
  1491. ) {
  1492.     if (screen_char_arry == NULL)
  1493.         maccur_init();
  1494.  
  1495.     maccur_noncurse_mode_show_str(str, &direct_curs_pos_row,
  1496.                                 &direct_curs_pos_col, NULL, TRUE,
  1497.                                 TRUE, FALSE);
  1498.  
  1499.     if (_maccur_io_sleep_dvsr > 0 && ++cpu_share_rot_cnt >= _maccur_io_sleep_dvsr)
  1500.     {
  1501.         maccur_cpu_share();
  1502.         cpu_share_rot_cnt = 0;
  1503.     }
  1504.  
  1505.     return 0;
  1506. }
  1507.  
  1508. /********
  1509. **
  1510. **    maccur_putchar:  Equivalent to putchar.
  1511. **
  1512. **    Returns:
  1513. **        Character printed.
  1514. **
  1515. **
  1516. ********/
  1517.  
  1518. int maccur_putchar(
  1519. char c
  1520. ) {
  1521.     char str[2];
  1522.  
  1523.     if (screen_char_arry == NULL)
  1524.         maccur_init();
  1525.  
  1526.     str[0] = c;
  1527.     str[1] = '\0';
  1528.  
  1529.     maccur_noncurse_mode_show_str(str, &direct_curs_pos_row,
  1530.                                 &direct_curs_pos_col, NULL, TRUE,
  1531.                                 FALSE, FALSE);
  1532.  
  1533.     if (_maccur_io_sleep_dvsr > 0 && ++cpu_share_rot_cnt >= _maccur_io_sleep_dvsr)
  1534.     {
  1535.         maccur_cpu_share();
  1536.         cpu_share_rot_cnt = 0;
  1537.     }
  1538.  
  1539.     return c;
  1540. }
  1541.  
  1542. /********
  1543. **
  1544. **    maccur_scanf:  Equivalent to scanf.  Uses THINK C's non-portable _vsscanf.
  1545. **
  1546. **    Returns:
  1547. **        Results of _vsscanf.
  1548. **
  1549. **
  1550. ********/
  1551.  
  1552. int    maccur_scanf(
  1553. char *fmt,
  1554. ...
  1555. ) {
  1556.     va_list args;
  1557.     int rtn;
  1558.  
  1559.     if (screen_char_arry == NULL)
  1560.         maccur_init();
  1561.  
  1562.     maccur_noncurse_mode_getstr(_curses_prntw, _curses_prntw_size, FALSE);
  1563.  
  1564.     va_start(args, fmt);
  1565.     rtn = _vsscanf(_curses_prntw, fmt, args);
  1566.     va_end(args);
  1567.  
  1568.     return rtn;
  1569. }
  1570.  
  1571. /********
  1572. **
  1573. **    maccur_gets:  Equivalent to gets.
  1574. **
  1575. **    Returns:
  1576. **        Pointer to string argument (success).
  1577. **
  1578. **
  1579. ********/
  1580.  
  1581. char *maccur_gets(
  1582. char *str
  1583. ) {
  1584.  
  1585.     if (screen_char_arry == NULL)
  1586.         maccur_init();
  1587.  
  1588.     if (maccur_noncurse_mode_getstr(str, -1, FALSE) == EOF)
  1589.         return NULL;
  1590.  
  1591.     return str;
  1592. }
  1593.  
  1594. /********
  1595. **
  1596. **    maccur_getchar:  Equivalent to getchar.
  1597. **
  1598. **    Returns:
  1599. **        Character read or EOF.
  1600. **
  1601. **
  1602. ********/
  1603.  
  1604. int maccur_getchar(void)
  1605. {
  1606.     char str[2];
  1607.     int rtn;
  1608.  
  1609.     if (screen_char_arry == NULL)
  1610.         maccur_init();
  1611.  
  1612.     if (maccur_noncurse_mode_getstr(str, 2, TRUE) == EOF)
  1613.         rtn = EOF;
  1614.     else
  1615.         rtn = str[0];
  1616.  
  1617.     return rtn;
  1618. }
  1619.